package com.csaba.connector.model;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;

import com.csaba.util.I18N;
import com.csaba.util.LoggerHelper;

/**
 * Root of all modell class. This class supports storing arbitrary values coming from the server.
 * <p> Normally modell classes defining there own properties, together with setter and getter methods
 * which are used for the business logic of the Csaba framework (for exampel account number or available
 * balance for Account objects). But usually the bank's providing more information, that can be stored as 
 * "RemoteProperties" through methods provided by this class. In this way the customer gets the maximum
 * information from the bank servers that is available on the public interfaces, although only the normal
 * properties of the modell classes are used in the framework.
 * <p>Remote properties are name-value pairs, where the name is a single String (for example "overdraft.limit")
 *  and the value is an Object (String, Date, Amount, etc...). As the names are not user friendly 
 *  names but codes, or system names, this object supports localization for property names. 
 *  For more information see {@link #getLocalizedName(String)}.
 * @author Gabe
 *
 */
public abstract class AbstractRemoteObject implements Serializable
{
	private static final long serialVersionUID = -7022991064389545816L;

	private final static Logger logger = LoggerHelper.getDefaultLogger();

	private final Map<String, Object> remoteProperties = new TreeMap<String, Object>();

	public void setRemoteProperty( final String name, final Object value )
	{
		if ( value == null )
		{
			logger.fine("Empty value cannot be set: id = " + name); //$NON-NLS-1$
			return;
		}
		remoteProperties.put(name, value);
	}

	public void copyRemoteProperty( final AbstractRemoteObject remoteObject )
	{
		remoteProperties.putAll(remoteObject.remoteProperties);
	}

	public boolean isRemotePropertySet( final String field )
	{
		return remoteProperties.containsKey(field);
	}

	public Object getRemoteProperty( final String field )
	{
		if ( remoteProperties.containsKey(field) )
			return remoteProperties.get(field);

		throw new IllegalArgumentException("Unsupported native field: " + field);
	}

	public Object removeRemoteProperty( final String field )
	{
		if ( remoteProperties.containsKey(field) )
			return remoteProperties.remove(field);

		throw new IllegalArgumentException("Unsupported native field: " + field);
	}

	/**
	 * Store localization string for each package. The resource bundle should be located in the same 
	 * package where the object model can be found. In case of missing resources the internal name
	 * or the property is provided back.<br>
	 * The resource file name should be <code>messages.properties</code>, and the content should
	 * account to the requirements of <code>java.util.ResourceBundle</code>.<br>
	 * The resource may contain translation per Entity bases, or generic description. For exmaple:
	 * <pre>
	 * account.number = Account number
	 * HistoryItem.account.number = Source account
	 * </pre>
	 * 
	 * 
	 * @see AbstractRemoteObject.getLocalizedName(), {@link I18N}
	 */
	public String getLocalizedName( final String propertyName )
	{
		return I18N.getString(this, propertyName);
	}

	public String[] getRemotePropertyNames()
	{
		final Set<String> keys = remoteProperties.keySet();
		final String[] keyArray = keys.toArray(new String[keys.size()]);
		Arrays.sort(keyArray);
		return keyArray;
	}

	public Map<String, Object> getRemoteProperties()
	{
		return remoteProperties;
	}
}
